﻿#region copyright
//                Copyright Andrew Rafas 2012.
// Distributed under the Eclipse Public License, Version 1.0.
//           (See accompanying file LICENSE.txt or 
//     copy at http://www.eclipse.org/legal/epl-v10.html)
#endregion
using System;
using System.Collections.Generic;

namespace CSFP.Memoize
{
    public class Model
    {
        static IValue<T> RecurseApply<T>(IList<IValue<T>> sourceList, Func<T, T, T> associativeFunction, int startIndex, int length)
        {
            if (length == 1)
                return sourceList[startIndex];
            int newlen1 = length / 2;
            int newstart2 = startIndex + newlen1;
            int newlen2 = length - newlen1;
            return new Function<T, T, T>(
                RecurseApply(sourceList, associativeFunction, startIndex, newlen1),
                RecurseApply(sourceList, associativeFunction, newstart2, newlen2), 
                associativeFunction);
        }

        public static IValue<T> Apply<T>(IList<IValue<T>> sourceList, Func<T, T, T> associativeFunction)
        {
            return RecurseApply(sourceList, associativeFunction, 0, sourceList.Count);
        }

        public static Source<T> Source<T>()
        {
            return new Source<T>();
        }

        public static SourceValue<T> SourceValue<T>() where T : IEquatable<T>
        {
            return new SourceValue<T>();
        }

        public static IValue<T> Constant<T>(T value)
        {
            return new Constant<T>(value);
        }

        public static Function<T, R> Function<T, R>(IValue<T> param, Func<T, R> pureFunction)
        {
            return new Function<T, R>(param, pureFunction);
        }

        public static Function<T1, T2, R> Function<T1, T2, R>(IValue<T1> param1, IValue<T2> param2, Func<T1, T2, R> pureFunction)
        {
            return new Function<T1, T2, R>(param1, param2, pureFunction);
        }

        public static Function<T1, T2, T3, R> Function<T1, T2, T3, R>(IValue<T1> param1, IValue<T2> param2, IValue<T3> param3, Func<T1, T2, T3, R> pureFunction)
        {
            return new Function<T1, T2, T3, R>(param1, param2, param3, pureFunction);
        }

        public static Function<T1, T2, T3, T4, R> Function<T1, T2, T3, T4, R>(IValue<T1> param1, IValue<T2> param2, IValue<T3> param3, IValue<T4> param4, Func<T1, T2, T3, T4, R> pureFunction)
        {
            return new Function<T1, T2, T3, T4, R>(param1, param2, param3, param4, pureFunction);
        }
    }
}
